#include "pw_pbl/Coroutine/QueueExecutor.hpp"
#include <cassert>
#include <pw_pbl/Coroutine.hpp>
#include <utility>

namespace pw_pbl::co
{
	static consteval QueueExecutor &exec() { return _co::ExecutorFactory<QueueExecutor>::instance(); }

	QueueExecutor::IAwaitable::~IAwaitable() noexcept
	{
		if (!resume_handler)
			return;
		auto rm = [this](SAwaitHead *pCur) {
			while (pCur->pNext)
			{
				if (pCur->pNext == this)
				{
					pCur->pNext = this->pNext;
					if (exec().pending_tail == this)
					{
						exec().pending_tail = pCur;
						assert(pCur->pNext == nullptr);
					}
					return true;
				}
				else
					pCur = pCur->pNext;
			}
			return false;
		};
		rm(&exec().running) || rm(&exec().pending);
	}

	void QueueExecutor::await_suspend(QueueExecutor::IAwaitable &fr) noexcept
	{
		exec().pending_tail->pNext = &fr;
		exec().pending_tail = &fr;
		fr.pNext = nullptr;
	}

	bool QueueExecutor::run(void) &
	{
		if (!pending.pNext)
			return true;
		running.pNext = std::exchange(pending.pNext, nullptr);
		pending_tail = &pending;
		while (running.pNext)
		{
			auto pCur = std::exchange(running.pNext, running.pNext->pNext);
			if (pCur->virtual_ready())
			{
				assert(pCur->resume_handler);
				std::exchange(pCur->resume_handler, nullptr).resume();
			}
			else
				await_suspend(*pCur);
		}

		return !pending.pNext;
	}
} // namespace pw_pbl::co
